package org.koin.dsl;

import org.junit.Assert;
import org.junit.Test;
import org.koin.Simple;
import org.koin.core.definition.BeanDefinition;
import org.koin.core.definition.Definition;
import org.koin.core.error.*;
import org.koin.core.module.Module;
import org.koin.core.parameter.DefinitionParameters;
import org.koin.core.scope.Scope;
import org.koin.test.KoinApplicationExt;

public class ModuleOptions {

    @Test
    public void module_default_options() {
        Module module = org.koin.dsl.Module.module(null);

        Assert.assertFalse(module.getCreateAtStart());
        Assert.assertFalse(module.getOverride());
    }

    @Test
    public void module_override_option() {
        Module module = org.koin.dsl.Module.module(true, null);

        Assert.assertFalse(module.getCreateAtStart());
        Assert.assertTrue(module.getOverride());
    }

    @Test
    public void module_created_options() {
        Module module = org.koin.dsl.Module.module(true, false, null);

        Assert.assertTrue(module.getCreateAtStart());
        Assert.assertFalse(module.getOverride());
    }

    @Test
    public void module_definitions_options_inheritance() throws ScopeAlreadyCreatedException, NoScopeDefFoundException {
        Module module = org.koin.dsl.Module.module(true, true, new ModuleDeclaration() {
            @Override
            public void invoke(Module module) {
                try {
                    module.single(Simple.ComponentA.class, new Definition<Simple.ComponentA>() {
                        @Override
                        public Simple.ComponentA invoke(Scope scope, DefinitionParameters parameters) {
                            return new Simple.ComponentA();
                        }
                    });
                } catch (DefinitionOverrideException e) {
                    e.printStackTrace();
                }
            }
        });

        org.koin.core.KoinApplication app = KoinApplication.koinApplication(new KoinAppDeclaration() {
            @Override
            public void invoke(org.koin.core.KoinApplication koinApplication) {
                try {
                    koinApplication.modules(module);
                } catch (DefinitionOverrideException e) {
                    e.printStackTrace();
                }
            }
        });

        Assert.assertTrue(module.getCreateAtStart());
        Assert.assertTrue(module.getOverride());

        BeanDefinition defA = KoinApplicationExt.getBeanDefinition(app.getKoin(), Simple.ComponentA.class);

        if (defA == null) {
            throw new IllegalStateException("no definition found");
        }
        Assert.assertTrue(defA.getOptions().isCreatedAtStart());
        Assert.assertTrue(defA.getOptions().isOverride());
    }

    @Test
    public void module_definitions_options_non_inheritance() throws ScopeAlreadyCreatedException, NoScopeDefFoundException {
        Module module = org.koin.dsl.Module.module(new ModuleDeclaration() {
            @Override
            public void invoke(Module module) {
                try {
                    module.single(Simple.ComponentA.class, null, true, false, new Definition<Simple.ComponentA>() {
                        @Override
                        public Simple.ComponentA invoke(Scope scope, DefinitionParameters parameters) {
                            return new Simple.ComponentA();
                        }
                    });

                    module.single(Simple.ComponentB.class, null, false, true, new Definition<Simple.ComponentB>() {
                        @Override
                        public Simple.ComponentB invoke(Scope scope, DefinitionParameters parameters) {
                            try {
                                return new Simple.ComponentB(scope.get(Simple.ComponentA.class));
                            } catch (ClosedScopeException e) {
                                e.printStackTrace();
                            } catch (DefinitionParameterException e) {
                                e.printStackTrace();
                            } catch (NoBeanDefFoundException e) {
                                e.printStackTrace();
                            }
                            return null;
                        }
                    });
                } catch (DefinitionOverrideException e) {
                    e.printStackTrace();
                }
            }
        });

        org.koin.core.KoinApplication app = KoinApplication.koinApplication(new KoinAppDeclaration() {
            @Override
            public void invoke(org.koin.core.KoinApplication koinApplication) {
                try {
                    koinApplication.modules(module);
                } catch (DefinitionOverrideException e) {
                    e.printStackTrace();
                }
            }
        });

        Assert.assertFalse(module.getCreateAtStart());
        Assert.assertFalse(module.getOverride());

        BeanDefinition defA = KoinApplicationExt.getBeanDefinition(app.getKoin(), Simple.ComponentA.class);

        if (defA == null) {
            throw new IllegalStateException("no definition found");
        }
        Assert.assertTrue(defA.getOptions().isCreatedAtStart());
        Assert.assertFalse(defA.getOptions().isOverride());

        BeanDefinition defB = KoinApplicationExt.getBeanDefinition(app.getKoin(), Simple.ComponentB.class);
        if (defB == null) {
            throw new IllegalStateException("no definition found");
        }
        Assert.assertFalse(defB.getOptions().isCreatedAtStart());
        Assert.assertTrue(defB.getOptions().isOverride());
    }
}
